package com.tomcat.mesos.tomcat.impl;

import com.tomcat.mesos.Constants;
import com.tomcat.mesos.tomcat.LaunchTomcat;

import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.nio.file.Files;
import java.util.concurrent.CountDownLatch;

/**
 * @author Rayn on 2015/12/23 13:09
 * @email liuwei412552703@163.com
 */
public class LaunchTomcatImpl implements LaunchTomcat, Closeable {

    final CountDownLatch latch = new CountDownLatch(1);

    final Tomcat tomcat;
    private final CuratorFramework zookeeper = null;

    final File webapps;
    final File work;

    public LaunchTomcatImpl() {
        this(new File("/temp"));
    }

    public LaunchTomcatImpl(File webapps) {
        if(null == webapps){
            throw new IllegalArgumentException("webapps 目录指定为空一异常。");
        }
        this.webapps = webapps;
        this.work = new File("work");

    }

    /**
     * 初始化
     */
    @Override
    public void init() {
        this.zookeeper = CuratorFrameworkFactory.newClient(System.getenv(Constants.ZOOKEEPER_QUORUM), new RetryOneTime(10000));

        this.tomcat = new Tomcat();

    }

    /**
     * 启动tomcat
     */
    @Override
    public void start() {
        zookeeper.start();
        if (!zookeeper.getZookeeperClient().blockUntilConnectedOrTimedOut())
        {
            LOG.error("Unable to connect to Zookeeper @{}", System.getenv(Constants.ZOOKEEPER_QUORUM));
            System.exit(1);
        }

        final Stat masterPathExist = zookeeper.checkExists().usingWatcher(new ZKMasterWatcher()).forPath(Constants.ZK_MASTER);
        if (masterPathExist == null)
        {
            throw new Exception("Master znode 没有创建.");
        }

        tomcat.getHost().setAppBase(this.webapps.getAbsolutePath());

        // Setup a standard HTTP connector
        final Connector connector = new Connector("HTTP/1.1");
        connector.setPort(0);
        tomcat.setConnector(connector);
        tomcat.getService().addConnector(connector);

        final File war = new File(System.getenv(Constants.WAR));

        LOG.info("{} size is {} bytes size", war.getAbsolutePath(), war.length());


        final File warDestination = new File(webapps, war.getName());
        LOG.info("Copy WAR {} to {}", war.getAbsolutePath(), warDestination.getAbsolutePath());
        Files.copy(war, warDestination);

        tomcat.addWebapp("/", warDestination.getAbsolutePath());
        tomcat.start();

        try {
            register();
        } catch (Exception e) {
            LOG.error("Error while registering slave", e);
            latch.countDown();
        }
        latch.await();
        LOG.info("Tomcat instance shutdown in progress");
        tomcat.stop();
    }

    /**
     *
     * @throws Exception
     */
    private void register() throws Exception
    {
        zookeeper.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(Constants.ZK_PREFFIX + "/slave-", data());
    }

    /**
     * 端口
     * @return
     */
    public int getPort()
    {
        return tomcat.getConnector().getLocalPort();
    }

    /**
     * 访问地址
     * @return
     * @throws Exception
     */
    private byte[] data() throws Exception
    {
        final String hostname = InetAddress.getLocalHost().getHostAddress();
        final StringBuilder sb = new StringBuilder(128);
        return sb.append("http://").append(hostname).append(':').append(getPort()).toString().getBytes(Charsets.UTF_8);
    }



    /**
     * 关闭tomcat
     *
     * @throws IOException
     */
    @Override
    public void close() throws IOException {
        try {
            if (zookeeper != null) {
                zookeeper.close();
            }
        } catch (Exception e) {
            LOG.error("Error while shutting down zookeeper client", e);
        }
        try {
            tomcat.stop();
        } catch (LifecycleException e) {
            LOG.error("Error while stopping Tomcat container", e);
        }
    }

    /**
     * Zookeeper master 监听
     */
    private class ZKMasterWatcher implements CuratorWatcher
    {
        @Override
        public void process(WatchedEvent watchedEvent) throws Exception
        {
            LOG.info("Tomcat container shutdown triggered from Zookeeper");
            latch.countDown();
        }
    }
}
